An Introduction to Radar Data in Pangeo Using Xradar + Py-ART
Overview
If you have an introductory paragraph, lead with it here! Keep it short and tied to your material, then be sure to continue into the required list of topics below,
Introduction to Py-ART 1.0
Introduction to xradar
The power of common data models
Visualization fun
Prerequisites
Concepts |
Importance |
Notes |
|---|---|---|
Necessary |
Familiarity with data model |
|
Necessary |
Familiarity with data model |
|
Helpful |
Familiarity with metadata structure |
|
Helpful |
Familiarity with radar science |
Time to learn: estimate in minutes. For a rough idea, use 5 mins per subsection, 10 if longer; add these up for a total. Safer to round up and overestimate.
System requirements:
Populate with any system, version, or non-Python software requirements if necessary
Otherwise use the concepts table above and the Imports section below to describe required packages as necessary
If no extra requirements, remove the System requirements point altogether
Imports
Begin your body of content with another --- divider before continuing into this section, then remove this body text and populate the following code cell with all necessary Python imports up-front:
import pyart
from open_radar_data import DATASETS
import xradar as xd
import xarray as xr
import hvplot.xarray
import holoviews as hv
import cartopy.crs as ccrs
import cmweather
import wradlib
hv.extension("bokeh")
## You are using the Python ARM Radar Toolkit (Py-ART), an open source
## library for working with weather radar data. Py-ART is partly
## supported by the U.S. Department of Energy as part of the Atmospheric
## Radiation Measurement (ARM) Climate Research Facility, an Office of
## Science user facility.
##
## If you use this software to prepare a publication, please cite:
##
## JJ Helmus and SM Collis, JORS 2016, doi: 10.5334/jors.119
An Introduction to Py-ART 1.0
This is where you begin your first section of material, loosely tied to your objectives stated up front. Tie together your notebook as a narrative, with interspersed Markdown text, images, and more as necessary,
Read in Data, Load into the Radar Object
Here, we use a sample file from a radar used for a field campaign in the Colorado Rockies!
file = DATASETS.fetch("gucxprecipradarcmacppiS2.c1.20220314.021559.nc")
file
Downloading file 'gucxprecipradarcmacppiS2.c1.20220314.021559.nc' from 'https://github.com/openradar/open-radar-data/raw/main/data/gucxprecipradarcmacppiS2.c1.20220314.021559.nc' to '/home/runner/.cache/open-radar-data'.
'/home/runner/.cache/open-radar-data/gucxprecipradarcmacppiS2.c1.20220314.021559.nc'
radar = pyart.io.read(file)
radar
/home/runner/miniconda3/envs/open-radar-pangeo-showcase-2024-dev/lib/python3.10/site-packages/pyart/io/cfradial.py:412: UserWarning: WARNING: valid_min not used since it
cannot be safely cast to variable data type
data = self.ncvar[:]
/home/runner/miniconda3/envs/open-radar-pangeo-showcase-2024-dev/lib/python3.10/site-packages/pyart/io/cfradial.py:412: UserWarning: WARNING: valid_max not used since it
cannot be safely cast to variable data type
data = self.ncvar[:]
<pyart.core.radar.Radar at 0x7f1d57106dd0>
Create a Quick Plot
One of Py-ART’s key benefits is the easy plotting classes users can utilize with their radar object!
More plotting examples in the gallery
display = pyart.graph.RadarDisplay(radar)
display.plot("corrected_reflectivity")
Ivestigate the radar object
But… how did we know that field was in there? What the heck is this object?
dir(radar)
['__class__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__getstate__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__setstate__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__',
'_check_sweep_in_range',
'_dic_info',
'add_field',
'add_field_like',
'add_filter',
'altitude',
'altitude_agl',
'antenna_transition',
'azimuth',
'check_field_exists',
'drift',
'elevation',
'extract_sweeps',
'fields',
'fixed_angle',
'gate_altitude',
'gate_latitude',
'gate_longitude',
'gate_x',
'gate_y',
'gate_z',
'georefs_applied',
'get_azimuth',
'get_elevation',
'get_end',
'get_field',
'get_gate_area',
'get_gate_lat_lon_alt',
'get_gate_x_y_z',
'get_nyquist_vel',
'get_slice',
'get_start',
'get_start_end',
'heading',
'info',
'init_gate_altitude',
'init_gate_longitude_latitude',
'init_gate_x_y_z',
'init_rays_per_sweep',
'instrument_parameters',
'iter_azimuth',
'iter_elevation',
'iter_end',
'iter_field',
'iter_slice',
'iter_start',
'iter_start_end',
'latitude',
'longitude',
'metadata',
'ngates',
'nrays',
'nsweeps',
'pitch',
'projection',
'radar_calibration',
'range',
'ray_angle_res',
'rays_are_indexed',
'rays_per_sweep',
'roll',
'rotation',
'scan_rate',
'scan_type',
'sweep_end_ray_index',
'sweep_mode',
'sweep_number',
'sweep_start_ray_index',
'target_scan_rate',
'tilt',
'time']
Where’s the data???
It’s all in the fields!
A dictionary of dictionaries… ahhh pre-xarray days…
radar.fields
{'DBZ': {'_FillValue': -32768.0,
'long_name': 'Equaivalent_radar_reflectiivity_factor',
'units': 'dBZ',
'standard_name': 'equivalent_reflectivity_factor',
'coordinates': 'elevation azimuth range',
'data': masked_array(
data=[[ 5.3499999 , 9.38999939, 9.60999966, ..., 7.50999975,
3.56999993, 7.52999973],
[ 6.85999966, 8.85999966, 8.43999958, ..., 7.50999975,
4.9000001 , 7.52999973],
[ 7.26999998, 8.97999954, 4.21999979, ..., 7.50999975,
4.9000001 , 7.52999973],
...,
[10.11999989, 8.34999943, 8.13999939, ..., 7.50999975,
7.51999998, 7.52999973],
[ 8.94999981, 6.36999989, 6.96000004, ..., 7.50999975,
7.51999998, 7.52999973],
[ 7.61999989, 6.30999994, 5.29999971, ..., 7.50999975,
7.51999998, 7.52999973]],
mask=False,
fill_value=1e+20)},
'VEL': {'_FillValue': -32768.0,
'long_name': 'Radial Doppler Velocity, Positive for Motion Away from Instrument',
'units': 'm/s',
'standard_name': 'radial_velocity_of_scatterers_away_from_instruments',
'coordinates': 'elevation azimuth range',
'data': masked_array(
data=[[ 1.76999998, 2.76999998, 3.74000001, ..., -6.37999964,
-1.14999998, -3.05999994],
[ 1.96999991, 2.54999995, 3.7099998 , ..., -5.19999981,
-3.05999994, -5.31999969],
[ 1.82999992, 2.78999996, 3.68999982, ..., -8.92999935,
-3.88999987, 13.27999973],
...,
[ 1.5999999 , 1.41999996, 2.08999991, ..., 3.52999997,
27.40999985, 23.70999908],
[ 1.56999993, 1.14999998, 2. , ..., 3.80999994,
-3.24000001, 23. ],
[ 1.5999999 , 1.30999994, 2.11999989, ..., 3.27999997,
-24.88999939, 0.38999999]],
mask=False,
fill_value=1e+20)},
'WIDTH': {'_FillValue': -32768.0,
'long_name': 'Spectral Width',
'units': 'm/s',
'standard_name': 'doppler_spectrum_width',
'coordinates': 'elevation azimuth range',
'data': masked_array(
data=[[1.69999993, 2.46000004, 1.17999995, ..., 3.30999994, 3.02999997,
2.12999988],
[1.75 , 2.26999998, 0.98999995, ..., 2.95000005, 3.63999987,
2.50999999],
[1.71999991, 2.19000006, 1.41999996, ..., 2.32999992, 3.77999997,
2.71000004],
...,
[1.01999998, 1.01999998, 0.63 , ..., 2.96000004, 3.01999998,
2.20000005],
[1.09000003, 1.18999994, 0.68000001, ..., 2.96000004, 2.78999996,
1.89999998],
[1.33999991, 1.25 , 0.88999999, ..., 2.25999999, 2.63999987,
2.91999984]],
mask=False,
fill_value=1e+20)},
'ZDR': {'_FillValue': -32768.0,
'long_name': 'Differential Reflectivity',
'units': 'dB',
'standard_name': 'log_differential_reflectivity_hv',
'coordinates': 'elevation azimuth range',
'data': masked_array(
data=[[1.85000007, 3.53999998, 2.97 , ..., 1.82999997, 3.60000001,
2.13000004],
[2.27000003, 3.80999999, 2.67 , ..., 2.32000004, 2.32000004,
2.56000002],
[2.71 , 3.84999995, 3.19999999, ..., 2.67 , 2.00000005,
2.54000001],
...,
[3.09 , 3.94999998, 3.02 , ..., 3.03 , 3.55999999,
2.54000001],
[3.49999999, 4.03999995, 2.98 , ..., 3.31999998, 2.36999999,
2.34000002],
[3.76999997, 3.57999997, 3.62999998, ..., 3.66000001, 2.15000002,
2.68 ]],
mask=False,
fill_value=1e+20)},
'PHIDP': {'_FillValue': -32768.0,
'long_name': 'Differential Phase',
'units': 'degree',
'standard_name': 'differential_phase_hv',
'coordinates': 'elevation azimuth range',
'data': masked_array(
data=[[ 89.95999908, 96.76999664, 98.90000153, ..., 280.95999908,
299.26000214, 293.23000336],
[ 94.04999542, 98.37999725, 99.62999725, ..., 282.26000214,
350.5 , 248.79000092],
[ 93.45999908, 100.20999908, 97.38999939, ..., 321.63999939,
329.46000099, 303.17000198],
...,
[ 98.29999542, 104.27999878, 102.98999786, ..., 59.59000015,
334.52000046, 333.11000061],
[ 98.63999939, 104.90999603, 101.22000122, ..., 27.56999969,
327.94000244, 315.49000168],
[ 99.16999817, 105.11999512, 106. , ..., 319.04999924,
349.60000038, 338.90999985]],
mask=False,
fill_value=1e+20)},
'RHOHV': {'_FillValue': -32768.0,
'long_name': 'Cross-Polar Correlation Ratio',
'units': '1',
'standard_name': 'cross_correlation_ratio_hv',
'coordinates': 'elevation azimuth range',
'data': masked_array(
data=[[0.97400004, 0.99200004, 0.99300003, ..., 0.70700002, 0.33100003,
0.46600002],
[0.96700007, 0.98200005, 0.98300004, ..., 0.81400001, 0.37300003,
0.45500001],
[0.95600003, 0.97800004, 0.96200007, ..., 0.53800005, 0.62200004,
0.44500002],
...,
[0.98000002, 0.98100007, 0.98200005, ..., 0.33600003, 0.38500002,
0.71100003],
[0.97000003, 0.97700006, 0.98300004, ..., 0.38200003, 0.45300001,
0.56700003],
[0.96000004, 0.98000002, 0.97500002, ..., 0.42800003, 0.54500002,
0.34800002]],
mask=False,
fill_value=1e+20)},
'NCP': {'_FillValue': -32768.0,
'long_name': 'Normalized Coherent Power, also known as SQI',
'units': '1',
'standard_name': 'normalized_coherent_power',
'coordinates': 'elevation azimuth range',
'data': masked_array(
data=[[0.90999997, 0.83999997, 0.91999996, ..., 0.16 , 0.14 ,
0.17 ],
[0.90999997, 0.85999995, 0.94999999, ..., 0.11 , 0.14 ,
0.22 ],
[0.89999998, 0.87 , 0.93000001, ..., 0.12 , 0.14 ,
0.22 ],
...,
[0.95999998, 0.95999998, 0.97999996, ..., 0.11 , 0.17999999,
0.13 ],
[0.95999998, 0.94 , 0.96999997, ..., 0.09999999, 0.14999999,
0.14999999],
[0.94999999, 0.93000001, 0.95999998, ..., 0.09999999, 0.11 ,
0.13 ]],
mask=False,
fill_value=1e+20)},
'DBZhv': {'_FillValue': -32768.0,
'long_name': 'Equivalent Reflectivity Factor HV',
'units': 'dBZ',
'standard_name': 'equivalent_reflectivity_factor_hv',
'coordinates': 'elevation azimuth range',
'data': masked_array(
data=[[ 6.39999962, 9.17000008, 9.55000019, ..., -0.76999998,
-1.81999993, -1.31999993],
[ 7.75999975, 7.86999989, 7.90999985, ..., -0.53999996,
-1.65999997, -1.52999997],
[ 7.46999979, 7.94999981, 2.42999983, ..., -0.22 ,
0.25999999, -1.25999999],
...,
[11.13999939, 9.40999985, 8.71000004, ..., -1.32999992,
-1.16999996, -2.3499999 ],
[ 9.28999996, 5.44999981, 7.51999998, ..., -0.57999998,
-0.44999999, -6. ],
[ 7.46000004, 4.26999998, 3.07999992, ..., -1.63 ,
-0.82999998, -3.02999997]],
mask=False,
fill_value=1e+20)},
'cbb_flag': {'long_name': 'Cumulative Beam Block Fraction Flag',
'units': '1',
'coordinates': 'elevation azimuth range',
'comment': 'Cumulative beam block flag due to terrain.',
'data': masked_array(
data=[[0., 0., 0., ..., 1., 1., 1.],
[0., 0., 0., ..., 1., 1., 1.],
[0., 0., 0., ..., 1., 1., 1.],
...,
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.]],
mask=False,
fill_value=1e+20)},
'sounding_temperature': {'long_name': 'Interpolated profile',
'units': 'degC',
'standard_name': 'interpolated_profile',
'data': masked_array(
data=[[ -2.3462055, -2.4152544, -2.4588518, ..., -34.118 ,
-34.18 , -34.232002 ],
[ -2.3462055, -2.4152544, -2.4588518, ..., -34.15 ,
-34.208 , -34.258 ],
[ -2.3462055, -2.4152544, -2.468688 , ..., -34.190002 ,
-34.24 , -34.278 ],
...,
[ -2.3565507, -2.4152544, -2.468688 , ..., -34.381226 ,
-34.42917 , -34.471428 ],
[ -2.3565507, -2.4152544, -2.468688 , ..., -34.381226 ,
-34.42917 , -34.471428 ],
[ -2.3565507, -2.4152544, -2.468688 , ..., -34.381226 ,
-34.42917 , -34.471428 ]],
mask=False,
fill_value=1e+20,
dtype=float32)},
'height': {'long_name': 'Height of radar beam',
'units': 'm',
'standard_name': 'height',
'data': masked_array(
data=[[3180.2, 3187.2, 3192.2, ..., 7398.2, 7405.2, 7411.2],
[3180.2, 3187.2, 3192.2, ..., 7402.2, 7408.2, 7415.2],
[3180.2, 3187.2, 3193.2, ..., 7406.2, 7412.2, 7418.2],
...,
[3181.2, 3187.2, 3193.2, ..., 7432.2, 7439.2, 7445.2],
[3181.2, 3187.2, 3193.2, ..., 7432.2, 7439.2, 7445.2],
[3181.2, 3187.2, 3193.2, ..., 7432.2, 7439.2, 7445.2]],
mask=False,
fill_value=1e+20,
dtype=float32)},
'signal_to_noise_ratio': {'_FillValue': -32768.0,
'long_name': 'Signal to Noise Ratio',
'units': 'dB',
'standard_name': 'signal_to_noise_ratio',
'coordinates': 'elevation azimuth range',
'data': masked_array(
data=[[40.18000031, 42.66999817, 41.56999969, ..., 0. ,
-3.94999981, 0. ],
[41.68999863, 42.13999939, 40.39999771, ..., 0. ,
-2.61999989, 0. ],
[42.09000015, 42.25 , 36.18000031, ..., 0. ,
-2.61999989, 0. ],
...,
[44.95000076, 41.62999725, 40.11000061, ..., 0. ,
0. , 0. ],
[43.77999878, 39.63999939, 38.91999817, ..., 0. ,
0. , 0. ],
[42.45000076, 39.59000015, 37.25999832, ..., 0. ,
0. , 0. ]],
mask=False,
fill_value=1e+20)},
'velocity_texture': {'long_name': 'Mean dopper velocity',
'units': 'm/s',
'standard_name': 'radial_velocity_of_scatterers_away_from_instrument',
'coordinates': 'elevation azimuth range',
'data': masked_array(
data=[[0.95980847, 0.88251601, 0.83554892, ..., 6.45901397, 5.62455843,
5.00792857],
[0.83920148, 0.83554892, 0.79410012, ..., 6.41084159, 5.62455843,
5.00792857],
[0.79410012, 0.73037925, 0.73037925, ..., 6.30690828, 6.02653167,
5.34782884],
...,
[0.29748918, 0.30600555, 0.45446138, ..., 5.26087378, 5.38360144,
5.38360144],
[0.29443759, 0.29443759, 0.45446138, ..., 4.9112846 , 5.22778187,
5.52338061],
[0.28717293, 0.28717293, 0.46040409, ..., 4.52095116, 5.10617287,
5.22778187]],
mask=False,
fill_value=1e+20)},
'gate_id': {'long_name': 'Classification of dominant scatterer',
'units': '1',
'notes': '0:multi_trip,1:rain,2:snow,3:no_scatter,4:melting,5:clutter,6:terrain_blockage',
'valid_max': '6',
'valid_min': '0',
'flag_values': '0, 1, 2, 3, 4, 5, 6',
'flag_meanings': 'multi_trip rain snow no_scatter melting clutter terrain_blockage',
'data': masked_array(
data=[[2, 2, 2, ..., 6, 6, 6],
[2, 2, 2, ..., 6, 6, 6],
[2, 2, 2, ..., 6, 6, 6],
...,
[2, 2, 2, ..., 3, 3, 3],
[2, 2, 2, ..., 3, 3, 3],
[2, 2, 2, ..., 3, 3, 3]],
mask=False,
fill_value=999999)},
'simulated_velocity': {'long_name': 'Simulated mean doppler velocity',
'units': 'm/s',
'standard_name': 'radial_velocity_of_scatterers_away_from_instrument',
'coordinates': 'elevation azimuth range',
'data': masked_array(
data=[[-4.04460068, -3.96199123, -3.94839799, ..., 12.92917905,
12.92917905, 12.96911246],
[-4.04456044, -3.96195182, -3.94835871, ..., 12.92905043,
12.93903185, 12.97896974],
[-4.03869838, -3.95620948, -3.92755288, ..., 13.0073836 ,
13.05760291, 13.05760536],
...,
[-4.02602798, -3.9593496 , -3.93067025, ..., 12.95954531,
12.95954531, 12.95954531],
[-4.02602798, -3.9593496 , -3.93067025, ..., 12.95954531,
12.95954531, 12.95954531],
[-4.02602798, -3.9593496 , -3.93067025, ..., 12.95954531,
12.95954531, 12.95954531]],
mask=False,
fill_value=1e+20)},
'corrected_velocity': {'_FillValue': -32768.0,
'long_name': 'Corrected mean doppler velocity',
'units': 'm/s',
'standard_name': 'corrected_radial_velocity_of_scatterers_away_from_instrument',
'coordinates': 'elevation azimuth range',
'valid_min': '-79.5',
'valid_max': '79.5',
'data': masked_array(
data=[[1.7699999809265137, 2.7699999809265137, 3.740000009536743, ...,
--, --, --],
[1.96999990940094, 2.549999952316284, 3.7099997997283936, ...,
--, --, --],
[1.8299999237060547, 2.7899999618530273, 3.68999981880188, ...,
--, --, --],
...,
[1.5999999046325684, 1.4199999570846558, 2.0899999141693115, ...,
--, --, --],
[1.5699999332427979, 1.149999976158142, 2.0, ..., --, --, --],
[1.5999999046325684, 1.309999942779541, 2.119999885559082, ...,
--, --, --]],
mask=[[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
...,
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True]],
fill_value=-32768.0)},
'unfolded_differential_phase': {'_FillValue': -32768.0,
'long_name': 'Unfolded differential propagation phase shift',
'units': 'degree',
'standard_name': 'differential_phase_hv',
'coordinates': 'elevation azimuth range',
'data': masked_array(
data=[[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
...,
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.]],
mask=False,
fill_value=1e+20)},
'corrected_differential_phase': {'_FillValue': -32768.0,
'long_name': 'Corrected differential propagation phase shift',
'units': 'degree',
'standard_name': 'differential_phase_hv',
'coordinates': 'elevation azimuth range',
'valid_min': '0.0',
'valid_max': '400.0',
'data': masked_array(
data=[[0.01, 0.01, 0.01, ..., 0.01, 0.01, 0.01],
[0.01, 0.01, 0.01, ..., 0.01, 0.01, 0.01],
[0.01, 0.01, 0.01, ..., 0.01, 0.01, 0.01],
...,
[0.01, 0.01, 0.01, ..., 0.01, 0.01, 0.01],
[0.01, 0.01, 0.01, ..., 0.01, 0.01, 0.01],
[0.01, 0.01, 0.01, ..., 0.01, 0.01, 0.01]],
mask=False,
fill_value=1e+20)},
'filtered_corrected_differential_phase': {'_FillValue': -32768.0,
'long_name': 'Filtered Corrected Differential Phase',
'units': 'degree',
'standard_name': 'differential_phase_hv',
'coordinates': 'elevation azimuth range',
'valid_min': '0.0',
'valid_max': '400.0',
'data': masked_array(
data=[[-4.36452341e-21, -1.30935702e-20, -2.61871405e-20, ...,
-6.05577610e-19, -6.05577610e-19, 1.00000000e-02],
[-4.36452341e-21, -1.30935702e-20, -2.61871405e-20, ...,
-5.55749303e-19, -5.55749303e-19, 1.00000000e-02],
[-4.36452341e-21, -1.30935702e-20, -2.61871405e-20, ...,
-4.88462899e-19, -4.88462899e-19, 1.00000000e-02],
...,
[-4.36452341e-21, -1.30935702e-20, -2.61871405e-20, ...,
-5.34654088e-19, -5.34654088e-19, 1.00000000e-02],
[-4.36452341e-21, -1.30935702e-20, -2.61871405e-20, ...,
-6.41221224e-19, -6.41221224e-19, 1.00000000e-02],
[-4.36452341e-21, -1.30935702e-20, -2.61871405e-20, ...,
-6.41221224e-19, -6.41221224e-19, 1.00000000e-02]],
mask=False,
fill_value=1e+20)},
'corrected_specific_diff_phase': {'_FillValue': -9999.0,
'long_name': 'Specific differential phase (KDP)',
'units': 'degrees/km',
'standard_name': 'specific_differential_phase_hv',
'coordinates': 'elevation azimuth range',
'data': masked_array(
data=[[-2.43197823e-20, -7.29593470e-20, -1.21598912e-19, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
[-2.43197823e-20, -7.29593470e-20, -1.21598912e-19, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
[-2.43197823e-20, -7.29593470e-20, -1.21598912e-19, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
...,
[-2.43197823e-20, -7.29593470e-20, -1.21598912e-19, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
[-2.43197823e-20, -7.29593470e-20, -1.21598912e-19, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
[-2.43197823e-20, -7.29593470e-20, -1.21598912e-19, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00]],
mask=False,
fill_value=1e+20)},
'filtered_corrected_specific_diff_phase': {'_FillValue': -9999.0,
'long_name': 'Filtered Corrected Specific differential phase (KDP)',
'units': 'degrees/km',
'standard_name': 'specific_differential_phase_hv',
'coordinates': 'elevation azimuth range',
'data': masked_array(
data=[[-2.43197823e-20, -7.29593470e-20, -1.21598912e-19, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
[-2.43197823e-20, -7.29593470e-20, -1.21598912e-19, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
[-2.43197823e-20, -7.29593470e-20, -1.21598912e-19, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
...,
[-2.43197823e-20, -7.29593470e-20, -1.21598912e-19, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
[-2.43197823e-20, -7.29593470e-20, -1.21598912e-19, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
[-2.43197823e-20, -7.29593470e-20, -1.21598912e-19, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00]],
mask=False,
fill_value=1e+20)},
'corrected_differential_reflectivity': {'_FillValue': 1e+20,
'long_name': 'Corrected differential reflectivity',
'units': 'dB',
'standard_name': 'corrected_log_differential_reflectivity_hv',
'coordinates': 'elevation azimuth range',
'data': masked_array(
data=[[1.8500000715255736, 3.5399999797344206, 2.970000001788139, ...,
--, --, --],
[2.2700000286102293, 3.8099999904632567, 2.6700000047683714, ...,
--, --, --],
[2.709999996423721, 3.849999952316284, 3.199999991059303, ...,
--, --, --],
...,
[3.08999999910593, 3.949999976158142, 3.020000000670552, ..., --,
--, --],
[3.499999988079071, 4.039999949932098, 2.9799999997019766, ...,
--, --, --],
[3.7699999690055845, 3.5799999713897703, 3.6299999833106993, ...,
--, --, --]],
mask=[[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
...,
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True]],
fill_value=1e+20)},
'corrected_reflectivity': {'_FillValue': 1e+20,
'long_name': 'Corrected reflectivity',
'units': 'dBZ',
'standard_name': 'corrected_equivalent_reflectivity_factor',
'coordinates': 'elevation azimuth range',
'data': masked_array(
data=[[5.349999904632568, 9.389999389648438, 9.609999656677246, ...,
--, --, --],
[6.859999656677246, 8.859999656677246, 8.4399995803833, ..., --,
--, --],
[7.269999980926514, 8.979999542236328, 4.21999979019165, ..., --,
--, --],
...,
[10.119999885559082, 8.34999942779541, 8.139999389648438, ...,
--, --, --],
[8.949999809265137, 6.369999885559082, 6.960000038146973, ...,
--, --, --],
[7.619999885559082, 6.309999942779541, 5.299999713897705, ...,
--, --, --]],
mask=[[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
...,
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True]],
fill_value=1e+20)},
'height_over_iso0': {'long_name': 'Height of radar beam over freezing level',
'units': 'm',
'standard_name': 'height',
'data': masked_array(
data=[[nan, nan, nan, ..., nan, nan, nan],
[nan, nan, nan, ..., nan, nan, nan],
[nan, nan, nan, ..., nan, nan, nan],
...,
[nan, nan, nan, ..., nan, nan, nan],
[nan, nan, nan, ..., nan, nan, nan],
[nan, nan, nan, ..., nan, nan, nan]],
mask=False,
fill_value=1e+20,
dtype=float32)},
'specific_attenuation': {'_FillValue': 1e+20,
'long_name': 'Specific attenuation',
'units': 'dB/km',
'standard_name': 'specific_attenuation',
'coordinates': 'elevation azimuth range',
'valid_min': '0.0',
'valid_max': '1.0',
'data': masked_array(
data=[[0.0, 0.0, 0.0, ..., --, --, --],
[0.0, 0.0, 0.0, ..., --, --, --],
[0.0, 0.0, 0.0, ..., --, --, --],
...,
[0.0, 0.0, 0.0, ..., --, --, --],
[0.0, 0.0, 0.0, ..., --, --, --],
[0.0, 0.0, 0.0, ..., --, --, --]],
mask=[[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
...,
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True]],
fill_value=1e+20)},
'path_integrated_attenuation': {'_FillValue': 1e+20,
'long_name': 'Path Integrated Attenuation',
'units': 'dB',
'coordinates': 'elevation azimuth range',
'data': masked_array(
data=[[0.0, 0.0, 0.0, ..., --, --, --],
[0.0, 0.0, 0.0, ..., --, --, --],
[0.0, 0.0, 0.0, ..., --, --, --],
...,
[0.0, 0.0, 0.0, ..., --, --, --],
[0.0, 0.0, 0.0, ..., --, --, --],
[0.0, 0.0, 0.0, ..., --, --, --]],
mask=[[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
...,
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True]],
fill_value=1e+20)},
'specific_differential_attenuation': {'_FillValue': 1e+20,
'long_name': 'Specific Differential Attenuation',
'units': 'dB/km',
'coordinates': 'elevation azimuth range',
'data': masked_array(
data=[[0.0, 0.0, 0.0, ..., --, --, --],
[0.0, 0.0, 0.0, ..., --, --, --],
[0.0, 0.0, 0.0, ..., --, --, --],
...,
[0.0, 0.0, 0.0, ..., --, --, --],
[0.0, 0.0, 0.0, ..., --, --, --],
[0.0, 0.0, 0.0, ..., --, --, --]],
mask=[[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
...,
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True]],
fill_value=1e+20)},
'path_integrated_differential_attenuation': {'_FillValue': 1e+20,
'long_name': 'Path Integrated Differential Attenuation',
'units': 'dB',
'coordinates': 'elevation azimuth range',
'data': masked_array(
data=[[0.0, 0.0, 0.0, ..., --, --, --],
[0.0, 0.0, 0.0, ..., --, --, --],
[0.0, 0.0, 0.0, ..., --, --, --],
...,
[0.0, 0.0, 0.0, ..., --, --, --],
[0.0, 0.0, 0.0, ..., --, --, --],
[0.0, 0.0, 0.0, ..., --, --, --]],
mask=[[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
...,
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True]],
fill_value=1e+20)},
'rain_rate_A': {'_FillValue': 1e+20,
'long_name': 'Rainfall Rate from Specific Attenuation',
'units': 'mm/hr',
'standard_name': 'rainfall_rate',
'coordinates': 'elevation azimuth range',
'least_significant_digit': 1,
'comment': 'Rain rate calculated from specific_attenuation, R=43.5*specific_attenuation**0.79, note R=0.0 where norm coherent power < 0.4 or rhohv < 0.8',
'valid_min': '0.0',
'valid_max': '400.0',
'data': masked_array(
data=[[0.0, 0.0, 0.0, ..., --, --, --],
[0.0, 0.0, 0.0, ..., --, --, --],
[0.0, 0.0, 0.0, ..., --, --, --],
...,
[0.0, 0.0, 0.0, ..., --, --, --],
[0.0, 0.0, 0.0, ..., --, --, --],
[0.0, 0.0, 0.0, ..., --, --, --]],
mask=[[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
...,
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True]],
fill_value=1e+20)},
'snow_rate_ws2012': {'_FillValue': 1e+20,
'long_name': 'Snowfall rate from Z using Wolf and Snider (2012)',
'units': 'mm/h',
'standard_name': 'snowfall_rate',
'coordinates': 'elevation azimuth range',
'valid_min': '0',
'valid_max': '500',
'swe_ratio': '13.699',
'A': '110',
'B': '2',
'data': masked_array(
data=[[0.17652395640137936, 0.28106296725172597, 0.28827278262198935,
..., --, --, --],
[0.2100407886358824, 0.2644256863269999, 0.25194377738869717,
..., --, --, --],
[0.22019307501812282, 0.2681042105157746, 0.1549899888164853,
..., --, --, --],
...,
[0.3057057811683439, 0.2493467022536862, 0.24339050225771308,
..., --, --, --],
[0.267179816896248, 0.19851971895737944, 0.21247295567206081,
..., --, --, --],
[0.22924699505759605, 0.19715312012338218, 0.1755107180920355,
..., --, --, --]],
mask=[[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
...,
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True]],
fill_value=1e+20)},
'snow_rate_ws88diw': {'_FillValue': 1e+20,
'long_name': 'Snowfall rate from Z using WSR 88D High Plains',
'units': 'mm/h',
'standard_name': 'snowfall_rate',
'coordinates': 'elevation azimuth range',
'valid_min': '0',
'valid_max': '500',
'swe_ratio': '13.699',
'A': '40',
'B': '2',
'data': masked_array(
data=[[0.2927318649462153, 0.46609020241896115, 0.47804632861441165,
..., --, --, --],
[0.3483132432877832, 0.4385003932394344, 0.4178014889315676, ...,
--, --, --],
[0.36514890563484625, 0.44460053549764045, 0.2570218195828306,
..., --, --, --],
...,
[0.5069556861889462, 0.4134947270439711, 0.4036174867624916, ...,
--, --, --],
[0.4430676021003563, 0.3292077106342157, 0.35234653603102045,
..., --, --, --],
[0.3801631334612524, 0.3269414628485627, 0.29105159929856145,
..., --, --, --]],
mask=[[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
...,
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True]],
fill_value=1e+20)},
'snow_rate_m2009_1': {'_FillValue': 1e+20,
'long_name': 'Snowfall rate from Z using Matrosov et al.(2009) Braham(1990) 1',
'units': 'mm/h',
'standard_name': 'snowfall_rate',
'coordinates': 'elevation azimuth range',
'valid_min': '0',
'valid_max': '500',
'swe_ratio': '13.699',
'A': '67',
'B': '1.28',
'data': masked_array(
data=[[0.09802747200957339, 0.2027555554981298, 0.21094065176843244,
..., --, --, --],
[0.1286223776774802, 0.18431748402559525, 0.17090470838886448,
..., --, --, --],
[0.13846748651837235, 0.1883395483532741, 0.07999568175760745,
..., --, --, --],
...,
[0.23120863590817595, 0.16816002594348523, 0.1619259720053442,
..., --, --, --],
[0.18732588605183864, 0.11777016986310176, 0.130957104270401,
..., --, --, --],
[0.14746588157528065, 0.116505869632889, 0.09714971660031632,
..., --, --, --]],
mask=[[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
...,
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True]],
fill_value=1e+20)},
'snow_rate_m2009_2': {'_FillValue': 1e+20,
'long_name': 'Snowfall rate from Z using Matrosov et al.(2009) Braham(1990) 2',
'units': 'mm/h',
'standard_name': 'snowfall_rate',
'coordinates': 'elevation azimuth range',
'valid_min': '0',
'valid_max': '500',
'swe_ratio': '13.699',
'A': '114',
'B': '1.39',
'data': masked_array(
data=[[0.08037193357461173, 0.1569465818472422, 0.16277181979683336,
..., --, --, --],
[0.10321373456165439, 0.14375480980848285, 0.13409313722293925,
..., --, --, --],
[0.11046734559487273, 0.1466410189496867, 0.06665142582252989,
..., --, --, --],
...,
[0.17712092960144296, 0.13210879171494475, 0.12759210547463656,
..., --, --, --],
[0.14591408480746687, 0.09516685344560759, 0.10493775392442406,
..., --, --, --],
[0.11706141455918391, 0.09422565554197429, 0.0797089853078306,
..., --, --, --]],
mask=[[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
...,
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True]],
fill_value=1e+20)}}
Introduction to xradar
Re-writing the readers, coming to a community standard.
Reading data using xradar
We can read in a single elevation (ex. sweep_0)
first_sweep = xr.open_dataset(file, engine='cfradial1', group='sweep_0')
first_sweep
<xarray.Dataset> Size: 195MB
Dimensions: (azimuth: 1159, range: 668)
Coordinates:
time (azimuth) datetime64[ns] 9kB ...
* range (range) float32 3kB 306.9 ... 4...
elevation (azimuth) float32 5kB ...
* azimuth (azimuth) float32 5kB 0.05238 ....
latitude float64 8B ...
longitude float64 8B ...
altitude float64 8B ...
Data variables: (12/37)
DBZ (azimuth, range) float64 6MB ...
VEL (azimuth, range) float64 6MB ...
WIDTH (azimuth, range) float64 6MB ...
ZDR (azimuth, range) float64 6MB ...
PHIDP (azimuth, range) float64 6MB ...
RHOHV (azimuth, range) float64 6MB ...
... ...
snow_rate_m2009_1 (azimuth, range) float64 6MB ...
snow_rate_m2009_2 (azimuth, range) float64 6MB ...
sweep_number int32 4B ...
sweep_fixed_angle float32 4B ...
sweep_mode <U188 752B ...
nyquist_velocity (azimuth) float64 9kB ...or the full volume!
dt = xd.io.open_cfradial1_datatree(file)
dt
<xarray.DatasetView> Size: 1kB
Dimensions: (sweep: 1)
Dimensions without coordinates: sweep
Data variables:
sweep_group_name (sweep) <U7 28B 'sweep_0'
sweep_fixed_angle (sweep) float32 4B ...
latitude float64 8B ...
longitude float64 8B ...
altitude float64 8B ...
time_coverage_start |S192 192B ...
time_coverage_end |S192 192B ...
volume_number int32 4B ...
platform_type |S192 192B ...
instrument_type |S192 192B ...
primary_axis |S192 192B ...
Attributes:
Conventions: CF/Radial instrument_parameters ARM-1.3
comment: This is highly experimental and initial data. There are man...
references: See XSAPR Instrument Handbook
source: Atmospheric Radiation Measurement (ARM) program X-band Scan...
institution: U.S. Department of Energy Atmospheric Radiation Measurement...
history: created by jrobrien on cirrus127.ccs.ornl.gov at 2022-09-26...Remove duplicate rays - this will help later!
dt["sweep_0"] = xd.util.remove_duplicate_rays(dt["sweep_0"])
Create a quick plot of the data
dt = dt.xradar.georeference()
dt["sweep_0"]
<xarray.DatasetView> Size: 202MB
Dimensions: (azimuth: 1147, range: 668)
Coordinates:
time (azimuth) datetime64[ns] 9kB 20...
* range (range) float32 3kB 306.9 ... 4...
elevation (azimuth) float32 5kB 5.988 ......
* azimuth (azimuth) float32 5kB 0.05238 ....
latitude float64 8B 38.9
longitude float64 8B -106.9
altitude float64 8B 3.149e+03
crs_wkt int64 8B 0
x (azimuth, range) float32 3MB 0....
y (azimuth, range) float32 3MB 30...
z (azimuth, range) float32 3MB 3....
Data variables: (12/37)
DBZ (azimuth, range) float64 6MB ...
VEL (azimuth, range) float64 6MB ...
WIDTH (azimuth, range) float64 6MB ...
ZDR (azimuth, range) float64 6MB ...
PHIDP (azimuth, range) float64 6MB ...
RHOHV (azimuth, range) float64 6MB ...
... ...
snow_rate_m2009_1 (azimuth, range) float64 6MB ...
snow_rate_m2009_2 (azimuth, range) float64 6MB ...
sweep_number int32 4B ...
sweep_fixed_angle float32 4B ...
sweep_mode <U188 752B 'azimuth_surveillanc...
nyquist_velocity (azimuth) float64 9kB ...dt["sweep_0"]["corrected_reflectivity"].plot(x="x",
y="y",
cmap="ChaseSpectral",
vmin=-10,
vmax=30)
<matplotlib.collections.QuadMesh at 0x7f1d4c266320>
Plot along an azimuth with the power of xarray
DBZH = dt["sweep_0"]["corrected_reflectivity"]
# Select the northwest azimuth (315 degrees) to view reflectivity
DBZH.sel(azimuth=315., method='nearest').plot()
[<matplotlib.lines.Line2D at 0x7f1d4c19ef80>]
The power of common data models
Using wradlib - Z(S) estimating snowfall!
See the discussion here for a more thorough literature review of the different relationships, but we can relate the properties of the scatterers to snowfall rates, using a log relationship:
Z = liquid_equivalent_snowfall * A * (S ^ B)
wradlib has a helper accessor to calculate this for this, solving for the snowfall rate in mm/hr, https://docs.wradlib.org/en/stable/zr.html
Here, we use values suitable for the Intermountain West, as this radar is in the Colorado Rockies.
a = 40
b = 2
snowfall = DBZH.wrl.zr.z_to_r(a=a, b=b)
# Update the attributes
snowfall.attrs["standard_name"] = "snowfall_rate"
snowfall.attrs["long_name"] = "snwofall_rate"
/home/runner/miniconda3/envs/open-radar-pangeo-showcase-2024-dev/lib/python3.10/site-packages/wradlib/zr.py:62: RuntimeWarning: invalid value encountered in sqrt
return (z / a) ** (1.0 / b)
snowfall.plot(x="x",
y="y",
cmap="ChaseSpectral",
vmin=0,
vmax=1)
<matplotlib.collections.QuadMesh at 0x7f1d4c018b20>
Add this field back into our datatree!
dt["sweep_0"]["snowfall_rate"] = snowfall
Use Py-ART to grid this up!
radar = pyart.xradar.Xradar(dt)
radar
<xarray.DatasetView> Size: 1kB
Dimensions: (sweep: 1)
Dimensions without coordinates: sweep
Data variables:
sweep_group_name (sweep) <U7 28B 'sweep_0'
sweep_fixed_angle (sweep) float32 4B ...
latitude float64 8B 38.9
longitude float64 8B -106.9
altitude float64 8B 3.149e+03
time_coverage_start |S192 192B ...
time_coverage_end |S192 192B ...
volume_number int32 4B ...
platform_type |S192 192B ...
instrument_type |S192 192B ...
primary_axis |S192 192B ...
Attributes:
Conventions: CF/Radial instrument_parameters ARM-1.3
comment: This is highly experimental and initial data. There are man...
references: See XSAPR Instrument Handbook
source: Atmospheric Radiation Measurement (ARM) program X-band Scan...
institution: U.S. Department of Energy Atmospheric Radiation Measurement...
history: created by jrobrien on cirrus127.ccs.ornl.gov at 2022-09-26...grid = pyart.map.grid_from_radars(
[radar],
grid_shape=(21, 161, 161),
grid_limits=(
(
0.0,
5_000,
),
(-20_000., 20_000.),
(-20_000, 20_000.),
),
)
ds = grid.to_xarray()
ds.snowfall_rate.isel(z=1).plot(x='lon', y='lat')
<matplotlib.collections.QuadMesh at 0x7f1d4c22a8f0>
Danger
Not every method has been implemented for the xradar-radar object bridge. If you find an issue, open an issue!
Visualization fun
Let’s use some holoviz tools!
Create an Interactive PPI Plot
proj_crs = xd.georeference.get_crs(dt["sweep_0"].ds)
cart_crs = ccrs.Projection(proj_crs)
ref_plot = dt["sweep_0"]["corrected_reflectivity"].hvplot.quadmesh(x="x",
y="y",
cmap="ChaseSpectral",
rasterize=True,
height=500,
width=600,
title = "Refletivity (dBz)",
clim=(-10, 30))
ref_plot
snow_plot = dt["sweep_0"]["snowfall_rate"].hvplot.quadmesh(x="x",
y="y",
cmap="ChaseSpectral",
rasterize=True,
height=500,
width=600,
title = "Snowfall rate (mm/hr)",
clim=(0, 1))
snow_plot
(snow_plot + ref_plot).cols(1)
Summary
Within this notebook, we looked at the current methods of working with radar data in Python - using Py-ART and xradar!
What’s next?
Stay tuned - following along with the:
Resources and references
The Python ARM Radar Toolkit (Py-ART)
xradar
SAIL Radar Data
Atmospheric Radiation Measurement (ARM) user facility. 2022. CSU X-Band Precip Radar (XPRECIPRADAR) PPI Corrected Moments to Antenna Coord (XPRECIPRADARCMACPPI). 2022-03-01 to 2023-03-31, ARM Mobile Facility (GUC) Gunnison, CO; Supplemental Facility 2 (S2). Compiled by R. Jackson, Z. Sherman, S. Collis, J. O’Brien, M. Grover, B. Raut, A. Theisen, M. Tuftedal and D. Feldman. ARM Data Center. Data set accessed 2024-04-02 at http://dx.doi.org/10.5439/1883164.
